// 10_module_system.rs
// 演示 Rust 中的模块系统和包管理

// 1. 模块定义
// 模块使用 mod 关键字定义，可以嵌套
mod front_of_house {
    mod hosting {
        fn add_to_waitlist() {
            println!("添加客人到等待列表");
        }
        
        fn seat_at_table() {
            println!("引导客人到餐桌");
        }
    }
    
    mod serving {
        fn take_order() {
            println!("接受订单");
        }
        
        fn serve_food() {
            println!("上菜");
        }
        
        fn take_payment() {
            println!("收款");
        }
    }
}

// 2. 模块可见性
// 默认情况下，模块中的项是私有的，可以使用 pub 关键字使其变为公共的
mod back_of_house {
    pub struct Breakfast {
        pub toast: String,
        seasonal_fruit: String, // 私有字段
    }
    
    impl Breakfast {
        pub fn summer(toast: &str) -> Breakfast {
            Breakfast {
                toast: String::from(toast),
                seasonal_fruit: String::from("桃子"),
            }
        }
    }
    
    pub enum Appetizer {
        Soup,
        Salad,
    }
    
    pub fn fix_incorrect_order() {
        cook_order();
        serve_order();
    }
    
    fn cook_order() {
        println!("烹饪订单");
    }
    
    fn serve_order() {
        println!("服务订单");
    }
}

// 3. 使用 pub use 重导出名称
mod utils {
    pub mod math {
        pub fn add(a: i32, b: i32) -> i32 {
            a + b
        }
        
        pub fn subtract(a: i32, b: i32) -> i32 {
            a - b
        }
    }
    
    // 重导出 math 模块中的函数
    pub use self::math::{add, subtract};
}

// 4. 内联模块
pub mod games {
    pub fn play_game() {
        println!("玩游戏");
    }
}

// 5. 声明宏
#[macro_export] // 使宏在 crate 根可见
macro_rules! say_hello {
    () => {
        println!("Hello, macro!");
    };
}

// 6. 外部crate示例（这里只是演示语法，实际使用需要在Cargo.toml中添加依赖）
// extern crate rand; // 如果要使用rand crate，需要在Cargo.toml中添加依赖

pub fn run() {
    // 7. 使用路径访问模块中的项
    // 绝对路径从 crate 根开始
    crate::front_of_house::hosting::add_to_waitlist();
    
    // 相对路径从当前模块开始
    front_of_house::hosting::seat_at_table();
    
    // 8. 使用 use 语句引入路径
    use crate::front_of_house::serving;
    serving::take_order();
    serving::serve_food();
    
    // 9. 使用 as 关键字重命名导入
    use crate::front_of_house::hosting as customer_hosting;
    customer_hosting::add_to_waitlist();
    
    // 10. 导入结构体、枚举和函数
    use crate::back_of_house::Breakfast;
    let mut meal = Breakfast::summer("全麦");
    println!("早餐: 吐司 = {}, 季节水果 = {}", meal.toast, meal.seasonal_fruit);
    meal.toast = String::from("白面包");
    // meal.seasonal_fruit = String::from("苹果"); // 这会导致编译错误，因为 seasonal_fruit 是私有字段
    
    use crate::back_of_house::Appetizer;
    let order1 = Appetizer::Soup;
    let order2 = Appetizer::Salad;
    
    match order1 {
        Appetizer::Soup => println!("客人点了汤"),
        Appetizer::Salad => println!("客人点了沙拉"),
    }
    
    // 11. 使用公共函数
    back_of_house::fix_incorrect_order();
    // back_of_house::cook_order(); // 这会导致编译错误，因为 cook_order 是私有函数
    
    // 12. 使用重导出的函数
    use crate::utils::{add, subtract};
    let sum = add(5, 3);
    let diff = subtract(5, 3);
    println!("5 + 3 = {}, 5 - 3 = {}", sum, diff);
    
    // 13. 使用内联模块
    games::play_game();
    
    // 14. 使用宏
    say_hello!();
    
    // 15. 包和 Crate 结构说明
    // Rust 的代码组织: 
    // - Crate: 一个编译单元，可以是二进制crate或库crate
    // - 包: 包含一个或多个crate，由Cargo.toml文件定义
    // - 模块: 用于组织crate中的代码
    // 
    // 典型的项目结构:
    // my_project/
    // ├── Cargo.toml       # 包配置文件
    // ├── Cargo.lock       # 依赖锁定文件
    // └── src/
    //     ├── main.rs      # 二进制crate的入口点
    //     ├── lib.rs       # 库crate的入口点
    //     └── util/
    //         └── mod.rs   # 模块文件
    
    // 16. 使用 super 访问父模块
    // 在子模块中，可以使用 super 关键字访问父模块中的项
    
    // 17. 使用 self 访问当前模块
    // self 关键字引用当前模块
    
    // 18. 为了完整性，这里提一下文件模块
    // 如果有单独的文件，可以通过 mod 声明引入
    // 例如，如果有一个名为 `my_module.rs` 的文件，可以这样引入: 
    // mod my_module;
    // 
    // 如果有一个目录 `my_module` 和其中的 `mod.rs` 文件，可以这样引入: 
    // mod my_module; // 这会加载 my_module/mod.rs
    
    println!("\n模块系统示例演示完成！");
    println!("要运行特定的示例文件，请使用 cargo run --bin <文件名>");
    println!("要构建库crate，请使用 cargo build --lib");
    println!("要查看依赖图，请使用 cargo tree");
}